1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import com.google.common.primitives.Booleans;
21  import com.google.common.primitives.Ints;
22  import com.google.common.primitives.Longs;
23  
24  import java.util.Comparator;
25  
26  import javax.annotation.Nullable;
27  
28  /**
29   * A utility for performing a chained comparison statement. For example:
30   * <pre>   {@code
31   *
32   *   public int compareTo(Foo that) {
33   *     return ComparisonChain.start()
34   *         .compare(this.aString, that.aString)
35   *         .compare(this.anInt, that.anInt)
36   *         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
37   *         .result();
38   *   }}</pre>
39   *
40   * <p>The value of this expression will have the same sign as the <i>first
41   * nonzero</i> comparison result in the chain, or will be zero if every
42   * comparison result was zero.
43   *
44   * <p>Performance note: Even though the {@code ComparisonChain} caller always
45   * invokes its {@code compare} methods unconditionally, the {@code
46   * ComparisonChain} implementation stops calling its inputs' {@link
47   * Comparable#compareTo compareTo} and {@link Comparator#compare compare}
48   * methods as soon as one of them returns a nonzero result. This optimization is
49   * typically important only in the presence of expensive {@code compareTo} and
50   * {@code compare} implementations.
51   *
52   * <p>See the Guava User Guide article on <a href=
53   * "http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained#compare/compareTo">
54   * {@code ComparisonChain}</a>.
55   *
56   * @author Mark Davis
57   * @author Kevin Bourrillion
58   * @since 2.0
59   */
60  @GwtCompatible
61  public abstract class ComparisonChain {
62    private ComparisonChain() {}
63  
64    /**
65     * Begins a new chained comparison statement. See example in the class
66     * documentation.
67     */
68    public static ComparisonChain start() {
69      return ACTIVE;
70    }
71  
72    private static final ComparisonChain ACTIVE = new ComparisonChain() {
73      @SuppressWarnings("unchecked")
74      @Override public ComparisonChain compare(
75          Comparable left, Comparable right) {
76        return classify(left.compareTo(right));
77      }
78      @Override public <T> ComparisonChain compare(
79          @Nullable T left, @Nullable T right, Comparator<T> comparator) {
80        return classify(comparator.compare(left, right));
81      }
82      @Override public ComparisonChain compare(int left, int right) {
83        return classify(Ints.compare(left, right));
84      }
85      @Override public ComparisonChain compare(long left, long right) {
86        return classify(Longs.compare(left, right));
87      }
88      @Override public ComparisonChain compare(float left, float right) {
89        return classify(Float.compare(left, right));
90      }
91      @Override public ComparisonChain compare(double left, double right) {
92        return classify(Double.compare(left, right));
93      }
94      @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
95        return classify(Booleans.compare(right, left)); // reversed
96      }
97      @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
98        return classify(Booleans.compare(left, right));
99      }
100     ComparisonChain classify(int result) {
101       return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
102     }
103     @Override public int result() {
104       return 0;
105     }
106   };
107 
108   private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
109 
110   private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
111 
112   private static final class InactiveComparisonChain extends ComparisonChain {
113     final int result;
114 
115     InactiveComparisonChain(int result) {
116       this.result = result;
117     }
118     @Override public ComparisonChain compare(
119         @Nullable Comparable left, @Nullable Comparable right) {
120       return this;
121     }
122     @Override public <T> ComparisonChain compare(@Nullable T left,
123         @Nullable T right, @Nullable Comparator<T> comparator) {
124       return this;
125     }
126     @Override public ComparisonChain compare(int left, int right) {
127       return this;
128     }
129     @Override public ComparisonChain compare(long left, long right) {
130       return this;
131     }
132     @Override public ComparisonChain compare(float left, float right) {
133       return this;
134     }
135     @Override public ComparisonChain compare(double left, double right) {
136       return this;
137     }
138     @Override public ComparisonChain compareTrueFirst(boolean left, boolean right) {
139       return this;
140     }
141     @Override public ComparisonChain compareFalseFirst(boolean left, boolean right) {
142       return this;
143     }
144     @Override public int result() {
145       return result;
146     }
147   }
148 
149   /**
150    * Compares two comparable objects as specified by {@link
151    * Comparable#compareTo}, <i>if</i> the result of this comparison chain
152    * has not already been determined.
153    */
154   public abstract ComparisonChain compare(
155       Comparable<?> left, Comparable<?> right);
156 
157   /**
158    * Compares two objects using a comparator, <i>if</i> the result of this
159    * comparison chain has not already been determined.
160    */
161   public abstract <T> ComparisonChain compare(
162       @Nullable T left, @Nullable T right, Comparator<T> comparator);
163 
164   /**
165    * Compares two {@code int} values as specified by {@link Ints#compare},
166    * <i>if</i> the result of this comparison chain has not already been
167    * determined.
168    */
169   public abstract ComparisonChain compare(int left, int right);
170 
171   /**
172    * Compares two {@code long} values as specified by {@link Longs#compare},
173    * <i>if</i> the result of this comparison chain has not already been
174    * determined.
175    */
176   public abstract ComparisonChain compare(long left, long right);
177 
178   /**
179    * Compares two {@code float} values as specified by {@link
180    * Float#compare}, <i>if</i> the result of this comparison chain has not
181    * already been determined.
182    */
183   public abstract ComparisonChain compare(float left, float right);
184 
185   /**
186    * Compares two {@code double} values as specified by {@link
187    * Double#compare}, <i>if</i> the result of this comparison chain has not
188    * already been determined.
189    */
190   public abstract ComparisonChain compare(double left, double right);
191 
192   /**
193    * Compares two {@code boolean} values, considering {@code true} to be less
194    * than {@code false}, <i>if</i> the result of this comparison chain has not
195    * already been determined.
196    *
197    * @since 12.0
198    */
199   public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
200 
201   /**
202    * Compares two {@code boolean} values, considering {@code false} to be less
203    * than {@code true}, <i>if</i> the result of this comparison chain has not
204    * already been determined.
205    *
206    * @since 12.0 (present as {@code compare} since 2.0)
207    */
208   public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
209 
210   /**
211    * Ends this comparison chain and returns its result: a value having the
212    * same sign as the first nonzero comparison result in the chain, or zero if
213    * every result was zero.
214    */
215   public abstract int result();
216 }